﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Web;
using System.Web.UI;
using System.Globalization;

namespace GoogleMaps
{
	/// <summary>
	/// Marks a specific position on the map.
	/// </summary>
	public class GMarker : GLatLng, IGMarker
	{
		/// <summary>
		/// Initializes a new instance of the GMarker class.
		/// </summary>
		public GMarker()
		{
			GEvents = new GEventCollection();

			Clickable = true;
			BounceGravity = 1;
			AutoPan = true;
		}

		/// <summary>
		/// Renders the object by appending it to the stringbuilder that contains the JavaScript 
		/// for the related Google Map.
		/// </summary>
		/// <param name="js">A string builder containing the javascript that goes with the Google Map.</param>
		/// <param name="javaScriptVariableName">The namve of the JavaScript variable that is holding the map.</param>
		public void Render(StringBuilder js, String javaScriptVariableName)
		{
			string options = "";

			if (Draggable)
				options = "draggable:true";

			if (!String.IsNullOrEmpty(IconId))
				options = String.Format(CultureInfo.InvariantCulture, "{0}{1}icon:{2}", options, (options.Length > 0) ? "," : "", IconId);

			if (DragCrossMove)
				options = String.Format(CultureInfo.InvariantCulture, "{0}{1}dragCrossMove:true", options, (options.Length > 0) ? "," : "");
			
			if (!String.IsNullOrEmpty(Title))
				options = String.Format(CultureInfo.InvariantCulture, "{0}{1}title:{2}", options, (options.Length > 0) ? "," : "", HttpUtility.HtmlEncode(Title));
			
			if (!Clickable)
				options = String.Format(CultureInfo.InvariantCulture, "{0}{1}clickable:false", options, (options.Length > 0) ? "," : "");

			if (Bouncy)
				options = String.Format(CultureInfo.InvariantCulture, "{0}{1}bouncy:true", options, (options.Length > 0) ? "," : "");
			
			if (BounceGravity != 1)
				options = String.Format(CultureInfo.InvariantCulture, "{0}{1}bounceGravity:{2}", options, (options.Length > 0) ? "," : "", BounceGravity.ToString(CultureInfo.InvariantCulture));

			if (!AutoPan)
				options = String.Format(CultureInfo.InvariantCulture, "{0}{1}autoPan:false", options, (options.Length > 0) ? "," : "");

			if (options.Length > 0)
				options = String.Format(CultureInfo.InvariantCulture, ", {{{0}}}", options);

			if (GEvents == null || GEvents.Count == 0)
			{
				js.AppendFormat(CultureInfo.InvariantCulture, "{0}.addOverlay(new GMarker(new GLatLng({1}, {2}){3}));", javaScriptVariableName,
					Lat.ToString(CultureInfo.InvariantCulture), Lng.ToString(CultureInfo.InvariantCulture), options);
			}
			else
			{
				if (String.IsNullOrEmpty(Id))
					throw new InvalidOperationException(Properties.Resources.GMarkerIdRequired);
				js.AppendFormat(CultureInfo.InvariantCulture, "var {0} = new GMarker(new GLatLng({1}, {2}){3});", Id,
					Lat.ToString(CultureInfo.InvariantCulture), Lng.ToString(CultureInfo.InvariantCulture), options);

				foreach (GEvent ge in GEvents)
					ge.Render(js, Id);

				js.AppendFormat(CultureInfo.InvariantCulture, "{0}.addOverlay({1});", javaScriptVariableName, Id);
			}
		}

		/// <summary>
		/// Gets or sets the id that is used to create the javascript varialbe that holds this marker.
		/// </summary>
		public string Id { get; set; }

		/// <summary>
		/// Gets or sets a flag indicating that the marker will be draggable by users. Markers set up to be dragged 
		/// require more resources to set up than markers that are clickable. Any marker that is draggable 
		/// is also clickable, bouncy and auto-pan enabled by default. The default value for this option 
		/// is false.
		/// </summary>
		public bool Draggable { get; set; }

		/// <summary>
		/// Gets or sets the id of the icon that will be used when the maker is rendered.
		/// </summary>
		public string IconId { get; set; }

		/// <summary>
		/// When dragging markers normally, the marker floats up and away from the cursor. Setting this 
		/// value to true keeps the marker underneath the cursor, and moves the cross downwards instead. 
		/// The default value for this option is false.
		/// </summary>
		public bool DragCrossMove { get; set; }

		/// <summary>
		/// This string will appear as tooltip on the marker, i.e. it will work just as the title 
		/// attribute on HTML elements.
		/// </summary>
		public string Title { get; set; }

		/// <summary>
		/// Toggles whether or not the marker is clickable. Markers that are not clickable or draggable 
		/// are inert, consume less resources and do not respond to any events. The default value for this 
		/// option is true, i.e. if the option is not specified, the marker will be clickable.
		/// </summary>
		public bool Clickable { get; set; }

		/// <summary>
		/// Toggles whether or not the marker should bounce up and down after it finishes dragging. The 
		/// default value for this option is false.
		/// </summary>
		public bool Bouncy { get; set; }

		/// <summary>
		/// When finishing dragging, this number is used to define the acceleration rate of the marker 
		/// during the bounce down to earth. The default value for this option is 1.
		/// </summary>
		public int BounceGravity { get; set; }

		/// <summary>
		/// Auto-pan the map as you drag the marker near the edge. If the marker is draggable the default 
		/// value for this option is true. 
		/// </summary>
		public bool AutoPan { get; set; }

		/// <summary>
		/// Gets a collection of events that are wired to this marker.
		/// </summary>
		[PersistenceMode(PersistenceMode.InnerProperty)]
		public GEventCollection GEvents { get; private set; }
	}
}
